//SPDX-FileCopyrightText: Copyright 2022-2024 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package roadmap_user_api_serv

import (
	"context"
	"time"

	"atomgit.com/openlinksaas-org/api-server/dao"
	"atomgit.com/openlinksaas-org/api-server/dao/roadmap_dao"
	"atomgit.com/openlinksaas-org/proto-gen-go.git/roadmap_state_api"
	"atomgit.com/openlinksaas-org/proto-gen-go.git/roadmap_user_api"
	"github.com/google/uuid"
	"go.mongodb.org/mongo-driver/mongo"
)

func (apiImpl *RoadmapUserApiImpl) SetNote(ctx context.Context, req *roadmap_user_api.SetNoteRequest) (*roadmap_user_api.SetNoteResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &roadmap_user_api.SetNoteResponse{
			Code:   roadmap_user_api.SetNoteResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	roadmapItem, err := roadmap_dao.RoadmapInfoDao.Get(ctx, req.RoadmapId)
	if err != nil {
		return &roadmap_user_api.SetNoteResponse{
			Code:   roadmap_user_api.SetNoteResponse_CODE_NO_ROADMAP,
			ErrMsg: "路线图不存在",
		}, nil
	}
	if !(roadmapItem.PubState || roadmapItem.OwnerUserId == sessionItem.UserId) {
		return &roadmap_user_api.SetNoteResponse{
			Code:   roadmap_user_api.SetNoteResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	nodeItem, err := roadmap_dao.NodeDao.Get(ctx, req.RoadmapId, req.NodeId)
	if err != nil {
		return &roadmap_user_api.SetNoteResponse{
			Code:   roadmap_user_api.SetNoteResponse_CODE_NO_NODE,
			ErrMsg: "节点不存在",
		}, nil
	}

	nodeTitle := ""
	if nodeItem.BasicInfo.TopicData != nil {
		nodeTitle = nodeItem.BasicInfo.TopicData.Title
	}

	opId := uuid.NewString()
	nowTime := time.Now().UnixNano() / 1e6

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = roadmap_dao.NoteDao.Upsert(sessCtx, &roadmap_dao.NoteInfoDbItem{
			RoadmapId:    req.RoadmapId,
			NodeId:       req.NodeId,
			UserId:       sessionItem.UserId,
			Content:      req.Content,
			RoadmapTitle: roadmapItem.BasicInfo.Title,
			NodeTitle:    nodeTitle,
			TimeStamp:    nowTime,
		})
		if err != nil {
			return nil, err
		}
		//增加日志
		err = roadmap_dao.StateOpDao.Insert(sessCtx, &roadmap_dao.StateOpItemDbItem{
			OpId:         opId,
			RoadmapId:    req.RoadmapId,
			RoadmapTitle: roadmapItem.BasicInfo.Title,
			NodeId:       req.NodeId,
			OpType:       uint32(roadmap_state_api.STATE_OP_TYPE_STATE_OP_SET),
			TimeStamp:    nowTime,
			UserId:       sessionItem.UserId,
			StateData: roadmap_dao.StateDataDbItem{
				UserNoteState: &roadmap_dao.UserNoteStateDbItem{
					Title: nodeTitle,
				},
			},
		})
		if err != nil {
			return nil, err
		}
		err = roadmap_dao.NodeOpIndexDao.Insert(sessCtx, &roadmap_dao.NodeOpIndexDbItem{
			OpId:      opId,
			RoadmapId: req.RoadmapId,
			NodeId:    req.NodeId,
			TimeStamp: nowTime,
		})
		if err != nil {
			return nil, err
		}
		err = roadmap_dao.UserOpIndexDao.Insert(sessCtx, &roadmap_dao.UserOpIndexDbItem{
			OpId:      opId,
			UserId:    sessionItem.UserId,
			TimeStamp: nowTime,
		})
		if err != nil {
			return nil, err
		}
		return &roadmap_user_api.SetNoteResponse{
			Code: roadmap_user_api.SetNoteResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	return ret.(*roadmap_user_api.SetNoteResponse), nil
}

func (apiImpl *RoadmapUserApiImpl) ListNote(ctx context.Context, req *roadmap_user_api.ListNoteRequest) (*roadmap_user_api.ListNoteResponse, error) {
	emptyList := []*roadmap_user_api.NoteInfo{}

	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &roadmap_user_api.ListNoteResponse{
			Code:     roadmap_user_api.ListNoteResponse_CODE_WRONG_SESSION,
			ErrMsg:   "会话不存在",
			NoteList: emptyList,
		}, nil
	}
	roadmapItem, err := roadmap_dao.RoadmapInfoDao.Get(ctx, req.RoadmapId)
	if err != nil {
		return &roadmap_user_api.ListNoteResponse{
			Code:     roadmap_user_api.ListNoteResponse_CODE_NO_ROADMAP,
			ErrMsg:   "路线图不存在",
			NoteList: emptyList,
		}, nil
	}
	if !(roadmapItem.PubState || roadmapItem.OwnerUserId == sessionItem.UserId) {
		return &roadmap_user_api.ListNoteResponse{
			Code:     roadmap_user_api.ListNoteResponse_CODE_NO_PERMISSION,
			ErrMsg:   "没有权限",
			NoteList: emptyList,
		}, nil
	}

	noteItemList, err := roadmap_dao.NoteDao.ListByRoadmap(ctx, req.RoadmapId, req.FilterByNodeId, req.NodeId)
	if err != nil {
		return nil, err
	}

	//生成结果
	noteList := []*roadmap_user_api.NoteInfo{}
	for _, noteItem := range noteItemList {
		note := noteItem.ToNoteInfo()
		note.RoadmapExist = true
		note.CanUpdateRoadmap = roadmapItem.OwnerUserId == sessionItem.UserId
		noteList = append(noteList, note)
	}

	return &roadmap_user_api.ListNoteResponse{
		Code:     roadmap_user_api.ListNoteResponse_CODE_OK,
		NoteList: noteList,
	}, nil
}

func (apiImpl *RoadmapUserApiImpl) ListMyNote(ctx context.Context, req *roadmap_user_api.ListMyNoteRequest) (*roadmap_user_api.ListMyNoteResponse, error) {
	emptyList := []*roadmap_user_api.NoteInfo{}

	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &roadmap_user_api.ListMyNoteResponse{
			Code:     roadmap_user_api.ListMyNoteResponse_CODE_WRONG_SESSION,
			ErrMsg:   "会话不存在",
			NoteList: emptyList,
		}, nil
	}

	count, err := roadmap_dao.NoteDao.CountByUser(ctx, sessionItem.UserId, req.FilterByRoadmapId, req.RoadmapId)
	if err != nil {
		return nil, err
	}
	noteItemList, err := roadmap_dao.NoteDao.ListByUser(ctx, sessionItem.UserId, req.FilterByRoadmapId, req.RoadmapId, int64(req.Offset), int64(req.Limit))
	if err != nil {
		return nil, err
	}

	//获取路线图信息
	roadmapIdList := []string{}
	for _, noteItem := range noteItemList {
		roadmapIdList = append(roadmapIdList, noteItem.RoadmapId)
	}
	roadmapItemList, err := roadmap_dao.RoadmapInfoDao.ListById(ctx, roadmapIdList)
	if err != nil {
		return nil, err
	}
	roadmapItemMap := map[string]*roadmap_dao.RoadmapInfoDbItem{}
	for _, roadmapItem := range roadmapItemList {
		roadmapItemMap[roadmapItem.RoadmapId] = roadmapItem
	}

	//生成结果
	noteList := []*roadmap_user_api.NoteInfo{}
	for _, noteItem := range noteItemList {
		note := noteItem.ToNoteInfo()
		roadmapItem, ok := roadmapItemMap[noteItem.RoadmapId]
		if ok {
			note.RoadmapExist = roadmapItem.PubState || roadmapItem.OwnerUserId == sessionItem.UserId
			note.CanUpdateRoadmap = roadmapItem.OwnerUserId == sessionItem.UserId
		}
		noteList = append(noteList, note)
	}

	return &roadmap_user_api.ListMyNoteResponse{
		Code:       roadmap_user_api.ListMyNoteResponse_CODE_OK,
		TotalCount: count,
		NoteList:   noteList,
	}, nil
}

func (apiImpl *RoadmapUserApiImpl) RemoveNote(ctx context.Context, req *roadmap_user_api.RemoveNoteRequest) (*roadmap_user_api.RemoveNoteResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &roadmap_user_api.RemoveNoteResponse{
			Code:   roadmap_user_api.RemoveNoteResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	exist, err := roadmap_dao.NoteDao.Exist(ctx, sessionItem.UserId, req.RoadmapId, req.NodeId)
	if err != nil {
		return nil, err
	}
	if !exist {
		return &roadmap_user_api.RemoveNoteResponse{
			Code: roadmap_user_api.RemoveNoteResponse_CODE_OK,
		}, nil
	}
	roadmapTitle := ""
	roadmapItemList, err := roadmap_dao.RoadmapInfoDao.ListById(ctx, []string{req.RoadmapId})
	if err != nil {
		return nil, err
	}
	if len(roadmapItemList) > 0 {
		roadmapTitle = roadmapItemList[0].BasicInfo.Title
	}

	nodeTitle := ""
	nodeItemList, err := roadmap_dao.NodeDao.ListById(ctx, []string{roadmap_dao.GenNodeItemId(req.RoadmapId, req.NodeId)})
	if err != nil {
		return nil, err
	}
	if len(nodeItemList) > 0 {
		if nodeItemList[0].BasicInfo.TopicData != nil {
			nodeTitle = nodeItemList[0].BasicInfo.TopicData.Title
		}
	}

	opId := uuid.NewString()
	nowTime := time.Now().UnixNano() / 1e6

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		//删除note
		err = roadmap_dao.NoteDao.Remove(sessCtx, sessionItem.UserId, req.RoadmapId, req.NodeId)
		//增加日志
		err = roadmap_dao.StateOpDao.Insert(sessCtx, &roadmap_dao.StateOpItemDbItem{
			OpId:         opId,
			RoadmapId:    req.RoadmapId,
			RoadmapTitle: roadmapTitle,
			NodeId:       req.NodeId,
			OpType:       uint32(roadmap_state_api.STATE_OP_TYPE_STATE_OP_REMOVE),
			TimeStamp:    nowTime,
			UserId:       sessionItem.UserId,
			StateData: roadmap_dao.StateDataDbItem{
				UserNoteState: &roadmap_dao.UserNoteStateDbItem{
					Title: nodeTitle,
				},
			},
		})
		if err != nil {
			return nil, err
		}
		err = roadmap_dao.NodeOpIndexDao.Insert(sessCtx, &roadmap_dao.NodeOpIndexDbItem{
			OpId:      opId,
			RoadmapId: req.RoadmapId,
			NodeId:    req.NodeId,
			TimeStamp: nowTime,
		})
		if err != nil {
			return nil, err
		}
		err = roadmap_dao.UserOpIndexDao.Insert(sessCtx, &roadmap_dao.UserOpIndexDbItem{
			OpId:      opId,
			UserId:    sessionItem.UserId,
			TimeStamp: nowTime,
		})
		if err != nil {
			return nil, err
		}
		return &roadmap_user_api.RemoveNoteResponse{
			Code: roadmap_user_api.RemoveNoteResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	return ret.(*roadmap_user_api.RemoveNoteResponse), nil
}

func (apiImpl *RoadmapUserApiImpl) ListNoteRoadmap(ctx context.Context, req *roadmap_user_api.ListNoteRoadmapRequest) (*roadmap_user_api.ListNoteRoadmapResponse, error) {
	emptyList := []*roadmap_user_api.SimpleRoadmapInfo{}

	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &roadmap_user_api.ListNoteRoadmapResponse{
			Code:     roadmap_user_api.ListNoteRoadmapResponse_CODE_WRONG_SESSION,
			ErrMsg:   "会话不存在",
			InfoList: emptyList,
		}, nil
	}

	noteItemList, err := roadmap_dao.NoteDao.ListSimpleRoadmapInfo(ctx, sessionItem.UserId)
	if err != nil {
		return nil, err
	}
	infoList := []*roadmap_user_api.SimpleRoadmapInfo{}
	for _, noteItem := range noteItemList {
		infoList = append(infoList, &roadmap_user_api.SimpleRoadmapInfo{
			RoadmapId:    noteItem.RoadmapId,
			RoadmapTitle: noteItem.RoadmapTitle,
		})
	}
	return &roadmap_user_api.ListNoteRoadmapResponse{
		Code:     roadmap_user_api.ListNoteRoadmapResponse_CODE_OK,
		InfoList: infoList,
	}, nil
}
